import 'reflect-metadata';
import { Ajax, downLoad } from './YvanUIAjax';

/**
 * 提取返回值类型
 */
export type RType<T> = T extends (...args: any[]) => infer R ? R : any

/**
 * 提取返回值
 */
export type PType<T> = T extends (...args: infer P) => any ? P : never

/**
 * 服务代理包装类型
 */
export type Broker<T> = {
    [KEY in keyof T]: T[KEY] extends Function ? (...args: PType<T[KEY]>) => Promise<RType<T[KEY]>> : never
}

/**
 * @Api 接口调用
 */
export function brokerInvoke(serverUrl: string, method: string, args: any): Promise<any> {
    return new Promise((resolve, reject) => {
        const ajax: Ajax.Function = _.get(window, 'YvanUI.ajax');
        ajax({
            url: serverUrl + '@' + method,
            method: 'POST-JSON',
            data: args

        }).then(res => {
            resolve(res);

        }).catch(e => {
            reject(e);
        });
    })
}

/**
 * @Api 接口调用
 */
export function brokerPost(serverUrl: string, args: any): Promise<any> {
    return new Promise((resolve, reject) => {
        const ajax: Ajax.Function = _.get(window, 'YvanUI.ajax');
        ajax({
            url: "/restful" + serverUrl,
            method: 'POST-JSON',
            data: args
        }).then(res => {
            resolve(res);
        }).catch(e => {
            reject(e);
        });
    })
}

/**
 * @ApiImport 服务调用
 */
export function brokerExcelImport(serverUrl: string, method: string, args: any): Promise<any> {
    return new Promise((resolve, reject) => {
        const ajax: Ajax.Function = _.get(window, 'YvanUI.ajax');
        const file = args["args"][0];
        // args["args"].splice(0);
        ajax({
            url: serverUrl + '@' + method,
            method: 'POST-FILE',
            // headers: {
            //     '__upload__param': JSON.stringify(args)
            // },
            data: file /** 一定要有参数，没有参数报错 **/
        }).then(res => {
            resolve(res);
        }).catch(e => {
            reject(e);
        });
    })
}

/**
 * @ApiExport 服务调用
 */
export function brokerExcelExport(serverUrl: string, method: string, args: any): Promise<any> {
    return new Promise((resolve, reject) => {
        downLoad(serverUrl + '@' + method, args["args"][0] || "file.xlsx", args, {}, true);
    })
}

export function brokerExcelExportDataSource(serverUrl: string, method: string, args: any): Promise<any> {
    return new Promise((resolve, reject) => {
        downLoad(serverUrl + '@' + method, args["args"][0] || "file.xlsx", args, {}, true);
    })
}


/**
 * 新版 Yvan-Server API 代理
 */
declare type Proxy<T> = {
    [KEY in keyof T]: T[KEY] extends (...args: any) => any ?
    (...args: Parameters<T[KEY]>) => Promise<ReturnType<T[KEY]>>
    : never
}

/**
 * 新版 Yvan-Server 引入 API 的方式
 */
export function createProxy<T>(serviceType: T): Proxy<T> {
    const serviceProxy: any = serviceType;
    const result: any = {};

    _.each(serviceProxy.funcs, funName => {
        result[funName]= function () {
            return brokerInvoke(serviceProxy.invokeUrl, funName, {
                args: Array.prototype.slice.call(arguments)
            });
        };
    });

    return result;
}

/**
 * 新版 Yvan-Server 引入 excel导出 的方式
 */
export function createExcelExport<T>(serviceType: T): Proxy<T> {
    const serviceProxy: any = serviceType;
    const result: any = {};

    _.each(serviceProxy.funcs, funName => {
        result[funName]= function () {
            return brokerExcelExport(serviceProxy.invokeUrl, funName, {
                args: Array.prototype.slice.call(arguments)
            });
        };
    });

    return result;
}

/**
 * 新版 Yvan-Server 引入 excel导出 的方式
 */
export function createExcelImport<T>(serviceType: T): Proxy<T> {
    const serviceProxy: any = serviceType;
    const result: any = {};

    _.each(serviceProxy.funcs, funName => {
        result[funName]= function () {
            return brokerExcelImport(serviceProxy.invokeUrl, funName, {
                args: Array.prototype.slice.call(arguments)
            });
        };
    });

    return result;
}

/**
 * 创建服务代理
 */
export function createBroker<T extends new (...args: any) => any>(serviceType: T): Broker<InstanceType<T>> {

    const serviceProxy: any = serviceType;
    const result = {};

    // 具体参见 com.yvan.serverless.ServerLessServlet@doGet
    _.each(serviceProxy.funcs, fun => {
        _.set(result, fun, function () {
            return brokerInvoke(serviceProxy.invokeUrl, fun, {
                args: Array.prototype.slice.call(arguments)
            });
        });
    });

    _.each(serviceProxy.excelExports, fun => {
        _.set(result, fun, function () {
            return brokerExcelExport(serviceProxy.invokeUrl, fun, {
                args: Array.prototype.slice.call(arguments)
            });
        });
    });

    _.each(serviceProxy.excelExportDataSource, fun => {
        _.set(result, fun, function () {
            return brokerExcelExportDataSource(serviceProxy.invokeUrl, fun, {
                args: Array.prototype.slice.call(arguments)
            });
        });
    });

    _.each(serviceProxy.excelImports, fun => {
        _.set(result, fun, function () {
            return brokerExcelImport(serviceProxy.invokeUrl, fun, {
                args: Array.prototype.slice.call(arguments)
            });
        });
    });

    return <Broker<InstanceType<T>>>result;
}